#include "rc522.h"

uint8_t cardTypes[2];

void rc522_write_reg(struct rc522Stu *rc, uint8_t *addrNdata){
    addrNdata[0] = (addrNdata[0] << 1);

    HAL_GPIO_WritePin(rc->csPort, rc->csPin, GPIO_PIN_RESET);

        HAL_SPI_Transmit(rc->hspi, addrNdata, 2, 0xffff);
    
    HAL_GPIO_WritePin(rc->csPort, rc->csPin, GPIO_PIN_SET);
    addrNdata[0] = (addrNdata[0] >> 1);
}

uint8_t rc522_read_reg(struct rc522Stu *rc, uint8_t regAddr){
    uint8_t regR = (regAddr << 1) | 0x80;
    uint8_t reg2 = 0;
    HAL_GPIO_WritePin(rc->csPort, rc->csPin, GPIO_PIN_RESET);

        HAL_SPI_Transmit(rc->hspi, &regR, 1, 0xffff);
        HAL_SPI_Receive(rc->hspi, &reg2, 1, 0xffff);

    HAL_GPIO_WritePin(rc->csPort, rc->csPin, GPIO_PIN_SET);
    return reg2;
}

void rc522_set_bits(struct rc522Stu *rc, uint8_t regAddr, uint8_t mask){
    uint8_t buf[2];
    buf[0] = regAddr;
    buf[1] = rc522_read_reg(rc, regAddr);
    buf[1] |= mask;

    rc522_write_reg(rc, buf);
}

void rc522_reset_bits(struct rc522Stu *rc, uint8_t regAddr, uint8_t mask){
    uint8_t buf[2];
    buf[0] = regAddr;
    buf[1] = rc522_read_reg(rc, regAddr);
    buf[1] &= ~mask;

    rc522_write_reg(rc, buf);
}

void rc522_antenna_set(struct rc522Stu *rc, uint8_t antennaStatus){
    if(antennaStatus == 0){ // 关闭天线
        rc522_reset_bits(rc, RC522_REG_TxControlReg, 0x03);
    }else { // 开启天线
        rc522_set_bits(rc, RC522_REG_TxControlReg, 0x03);
    }
}


int rc522_init(struct rc522Stu *rc){
    uint8_t i = 0;
    uint8_t rcInitBuf[3] = {
        RC522_REG_CommandReg,
        RC522_CMD_SoftReset,
        0x00,
    };
    // 复位
    HAL_GPIO_WritePin(rc->rstPort, rc->rstPin, GPIO_PIN_SET);
    HAL_Delay(100);
    HAL_GPIO_WritePin(rc->rstPort, rc->rstPin, GPIO_PIN_RESET);
    HAL_Delay(100);
    HAL_GPIO_WritePin(rc->rstPort, rc->rstPin, GPIO_PIN_SET);
    HAL_Delay(100);

    rc522_write_reg(rc, rcInitBuf);
    HAL_Delay(1);
    while(rc522_read_reg(rc, rcInitBuf[0]) & 0x10){
        i ++;
        HAL_Delay(1);
        if(i > 200){
            return -1;
        }
    }

    rcInitBuf[0] = RC522_REG_CommandReg;
    rcInitBuf[1] = RC522_CMD_SoftReset;
    rc522_write_reg(rc, rcInitBuf);


    // 定义发送和接收常用模式和 Mifare 卡通讯，CRC 初始值 0x6363
    rcInitBuf[0] = RC522_REG_ModeReg;
    rcInitBuf[1] = 0x3D;
    rc522_write_reg(rc, rcInitBuf);
    
    // 16 位定时器
    rcInitBuf[0] = RC522_REG_TReloadRegL;
    rcInitBuf[1] = 30;
    rc522_write_reg(rc, rcInitBuf);
    rcInitBuf[0] = RC522_REG_TReloadRegH;
    rcInitBuf[1] = 0;
    rc522_write_reg(rc, rcInitBuf);

    // 设置内部定时器
    rcInitBuf[0] = RC522_REG_TModeReg;
    rcInitBuf[1] = 0x8D;
    rc522_write_reg(rc, rcInitBuf);
    rcInitBuf[0] = RC522_REG_TPrescalerReg;
    rcInitBuf[1] = 0x3E;
    rc522_write_reg(rc, rcInitBuf);

    // 调制发送信号为 100% ASK
    rcInitBuf[0] = RC522_REG_TxAutoReg;
    rcInitBuf[1] = 0x40;
    rc522_write_reg(rc, rcInitBuf);

/*
    // 设置工作方式 ISO14443_A
    rc522_reset_bits(rc, RC522_REG_Status2Reg, 0x08);

    rcInitBuf[0] = RC522_REG_ModeReg;
    rcInitBuf[1] = 0x3D;
    rc522_write_reg(rc, rcInitBuf);

    rcInitBuf[0] = RC522_REG_RxSelReg;
    rcInitBuf[1] = 0x86;
    rc522_write_reg(rc, rcInitBuf);
    
    rcInitBuf[0] = RC522_REG_RFCfgReg;
    rcInitBuf[1] = 0x7F;
    rc522_write_reg(rc, rcInitBuf);
    
    rcInitBuf[0] = RC522_REG_TReloadRegL;
    rcInitBuf[1] = 30;
    rc522_write_reg(rc, rcInitBuf);
    
    rcInitBuf[0] = RC522_REG_TReloadRegH;
    rcInitBuf[1] = 0;
    rc522_write_reg(rc, rcInitBuf);
    
    rcInitBuf[0] = RC522_REG_TModeReg;
    rcInitBuf[1] = 0x8D;
    rc522_write_reg(rc, rcInitBuf);

    rcInitBuf[0] = RC522_REG_TPrescalerReg;
    rcInitBuf[1] = 0x3E;
    rc522_write_reg(rc, rcInitBuf);
*/
    HAL_Delay(1);
    rc522_antenna_set(rc, 1);

    return 0;
}

// 卡片通信
uint8_t rc522_card_communication(struct rc522Stu *rc, uint8_t cmd, uint8_t *dataIn, uint8_t lengthIn, uint8_t *dataOut, uint32_t *lengthOutBits){
    uint8_t buf[2];
    uint16_t i;
    uint8_t errNum = 0;
    uint8_t readData;
    uint8_t irqEn = 0x00;
    uint8_t waitFor = 0x00;
    uint8_t lastBits;

    switch(cmd){
        case RC522_CMD_Authent:
            irqEn = 0x12;
            waitFor = 0x10;
            break;
            
        case RC522_CMD_Transceive:
            irqEn = 0x77;
            waitFor = 0x30;
            break;

        default:
            printf_DMA(PRINT_ERROR"Unknown cmd for %s: %d\n", __FUNCTION__, cmd);
            return 0xFF;
            break;
    }

    buf[0] = RC522_REG_ComIEnReg;
    buf[1] = irqEn | 0x80;
    rc522_write_reg(rc, buf);

    rc522_reset_bits(rc, RC522_REG_ComIrqReg, 0x80); // 清除所有中断位

    buf[0] = RC522_REG_CommandReg;
    buf[1] = RC522_CMD_Idle;
    rc522_write_reg(rc, buf);

    rc522_set_bits(rc, RC522_REG_FIFOLevelReg, 0x80); // 清除 FIFO 缓存

    // buf[0] = RC522_REG_FIFODataReg;
    for(i = 0; i < lengthIn; i ++){
        buf[0] = RC522_REG_FIFODataReg;
        buf[1] = dataIn[i];
        rc522_write_reg(rc, buf);
        HAL_Delay(1);
    }
    
    buf[0] = RC522_REG_CommandReg;
    buf[1] = cmd;
    rc522_write_reg(rc, buf);

    if(cmd == RC522_CMD_Transceive){
        rc522_set_bits(rc, RC522_REG_BitFramingReg, 0x80); // 开始传送
    }

    i = 1000; // < 1250
    do{
        readData = rc522_read_reg(rc, RC522_REG_ComIrqReg);
        i --;
    }while((i!=0) && (!(readData&0x01)) && (!(readData&waitFor)));

    rc522_reset_bits(rc, RC522_REG_BitFramingReg, 0x80);

    if(i != 0){
        if(!(rc522_read_reg(rc, RC522_REG_ErrorReg) & 0x1B)){
            errNum = RC522_ERR_OK;
            if(readData & irqEn & 0x01){
                errNum = RC522_ERR_NOCARD;
            }
            if(cmd == RC522_CMD_Transceive){
                readData = rc522_read_reg(rc, RC522_REG_FIFOLevelReg);
                lastBits = rc522_read_reg(rc, RC522_REG_ControlReg) & 0x07;
                if(lastBits){
                    *lengthOutBits = (readData - 1)*8 + lastBits;
                }else {
                    *lengthOutBits = readData * 8;
                }
                if(readData == 0){
                    readData = 1;
                }
                if(readData > RC522_REC_MAXLEN){
                    readData = RC522_REC_MAXLEN;
                }
                for(i = 0; i < readData; i ++){
                    HAL_Delay(1);
                    dataOut[i] = rc522_read_reg(rc, RC522_REG_FIFODataReg);
                }

            }
        }else {
            errNum = RC522_ERR_ERR;
        }
    }else {
        printf_DMA(PRINT_DEBUG"Rc522 communication time out\n");
    }

    rc522_set_bits(rc, RC522_REG_ControlReg, 0x80);
    
    buf[0] = RC522_REG_CommandReg;
    buf[1] = RC522_CMD_Idle;
    rc522_write_reg(rc, buf);

    return errNum;
}

// 寻找符合类型的卡
uint8_t rc522_card_request(struct rc522Stu *rc, uint8_t reqCode, uint8_t *cardType){
    uint8_t errNum;
    uint8_t buf[2];
    uint8_t comBuf[RC522_REC_MAXLEN];
    uint32_t comRecLen;

    rc522_reset_bits(rc, RC522_REG_Status2Reg, 0x08);

    buf[0] = RC522_REG_BitFramingReg;
    buf[1] = 0x07;
    rc522_write_reg(rc, buf);

    // rc522_set_bits(rc, RC522_REG_TxControlReg, 0x03);

    comBuf[0] = reqCode;
    errNum = rc522_card_communication(rc, RC522_CMD_Transceive, comBuf, 1, comBuf, &comRecLen);
    if(errNum == RC522_ERR_OK){
        if(comRecLen == 0x10){
            *cardType = comBuf[0];
            *(cardType+1) = comBuf[1];
            printf_DMA(PRINT_DEBUG"Find card, type: 0x%x 0x%x\n", cardType[0], cardType[1]);
        }else {
            errNum = RC522_ERR_ERR;
        }
    }

    return errNum;
}

// 防冲撞
uint8_t rc522_card_anticoll(struct rc522Stu *rc, uint8_t *cardID){
    uint8_t errNum, i, idCheck = 0;
    uint32_t comLen;
    uint8_t buf[2];
    uint8_t comBuf[RC522_REC_MAXLEN];

    rc522_reset_bits(rc, RC522_REG_Status2Reg, 0x08);

    buf[0] = RC522_REG_BitFramingReg;
    buf[1] = 0x00;
    rc522_write_reg(rc, buf);
    
    rc522_reset_bits(rc, RC522_REG_CollReg, 0x80);

    comBuf[0] = CARD_ANTICOLL1;
    comBuf[1] = 0x20;
    errNum = rc522_card_communication(rc, RC522_CMD_Transceive, comBuf, 2, comBuf, &comLen);
    if(errNum == RC522_ERR_OK){
        printf_DMA(PRINT_DEBUG"Recived bits: %d\n", comLen);
        for(i = 0; i < 4; i ++){
            *(cardID + i) = comBuf[i];
            idCheck ^= comBuf[i];
            printf_DMA(PRINT_DEBUG"cardID[%d] = 0x%x\n", i, comBuf[i]);
        }
        printf_DMA(PRINT_DEBUG"idCheck = 0x%x, buf[4] = 0x%x\n", idCheck, comBuf[i]);
        if(idCheck != comBuf[i]){
            printf_DMA(PRINT_DEBUG"Card id check Error!\n");
            errNum = RC522_ERR_ERR;
        }
    }

    rc522_set_bits(rc, RC522_REG_CollReg, 0x80);

    return errNum;
}

void rc522_card_CRC(struct rc522Stu *rc, uint8_t *dataIn, uint8_t len, uint8_t *dataOut){
    uint8_t i, n;
    uint8_t buf[2];

    rc522_reset_bits(rc, RC522_REG_DivIrqReg, 0x04);

    buf[0] = RC522_REG_CommandReg;
    buf[1] = RC522_CMD_Idle;
    rc522_write_reg(rc, buf);

    rc522_set_bits(rc, RC522_REG_FIFOLevelReg, 0x80);


    // buf[0] = RC522_REG_FIFODataReg;
    for(i = 0; i < len; i ++){
        HAL_Delay(1);
        buf[0] = RC522_REG_FIFODataReg;
        buf[1] = *(dataIn + i);
        rc522_write_reg(rc, buf);
    }
    
    buf[0] = RC522_REG_CommandReg;
    buf[1] = RC522_CMD_CalcCRC;
    rc522_write_reg(rc, buf);

    i = 0xFF;
    do {
        n = rc522_read_reg(rc, RC522_REG_DivIrqReg);
        i --;
    }while((i != 0) && !(n & 0x04));
    dataOut[0] = rc522_read_reg(rc, RC522_REG_CRCResultRegL);
    dataOut[1] = rc522_read_reg(rc, RC522_REG_CRCResultRegM);
}

// 选卡
uint8_t rc522_card_select(struct rc522Stu *rc, uint8_t *cardID){
    uint8_t errNum, i;
    uint32_t comLen;
    uint8_t comBuf[RC522_REC_MAXLEN];

    comBuf[0] = CARD_ANTICOLL1;
    comBuf[1] = 0x70;
    comBuf[6] = 0;

    for(i = 0; i < 4; i ++){
        comBuf[i + 2] = *(cardID + i);
        comBuf[6] ^= *(cardID + i);
    }
    rc522_card_CRC(rc, comBuf, 7, &comBuf[7]);

    rc522_reset_bits(rc, RC522_REG_Status2Reg, 0x08);

    errNum = rc522_card_communication(rc, RC522_CMD_Transceive, comBuf, 9, comBuf, &comLen);
    if((errNum == RC522_ERR_OK) && (comLen == 0x18)){
        errNum = RC522_ERR_OK;
    }else {
        errNum = RC522_ERR_ERR;
    }
    
    return errNum;
}

// 验证卡片
uint8_t rc522_card_identificate(struct rc522Stu *rc, uint8_t *cardType, uint8_t *cardID){
    uint8_t errNum;
    uint8_t cStatus = 0;

    errNum = rc522_card_request(rc, CARD_REQALL, cardType);
    if(errNum == RC522_ERR_OK){ // 寻卡成功
        cStatus |= 0x01;
        if(rc522_card_anticoll(rc, cardID) == RC522_ERR_OK){ // 防冲撞成功
            cStatus |= 0x02;
            if(rc522_card_select(rc, cardID) == RC522_ERR_OK){ // 选卡成功
                cStatus |= 0x04;
            }else {
                printf_DMA(PRINT_WARNNING"Select card Failed!\n");
            }
        }else {
            printf_DMA(PRINT_WARNNING"Anticoll card Failed!\n");
        }
    }else if(errNum == RC522_ERR_NOCARD){
        return RC522_ERR_NOCARD;
    }else {
        printf_DMA(PRINT_WARNNING"Request card Failed!\n");
    }

    if(cStatus == 0x07){
        return RC522_ERR_OK;
    }
    return RC522_ERR_ERR;
}

// 验证密码
uint8_t rc522_card_auth_state(struct rc522Stu *rc, uint8_t authMode, uint8_t addr, uint8_t *key, uint8_t *cardID){
    uint8_t errNum, i;
    uint32_t comLen;
    uint8_t comBuf[RC522_REC_MAXLEN];

    comBuf[0] = authMode;
    comBuf[1] = addr;
    for(i = 0; i < 6; i ++){
        comBuf[2 + i] = *(key + i);
    }
    for(i = 0; i < 4; i ++){
        comBuf[8 + i] = *(cardID + i);
    }

    errNum = rc522_card_communication(rc, RC522_CMD_Authent, comBuf, 12, comBuf, &comLen);
    if((errNum != RC522_ERR_OK) || (!(rc522_read_reg(rc, RC522_REG_Status2Reg) & 0x08))){
        printf_DMA(PRINT_DEBUG"card auth errCode: %d\n", errNum);
        return RC522_ERR_PASSWORD;
    }
    return RC522_ERR_OK;
}

uint8_t rc522_card_read_block(struct rc522Stu *rc, uint8_t authMode, uint8_t addr, uint8_t *key, uint8_t *data, uint8_t *cardID){
    uint8_t errNum, i;
    uint32_t comLen;
    uint8_t comBuf[RC522_REC_MAXLEN];

    errNum = rc522_card_identificate(rc, cardTypes, cardID);
    if(errNum == RC522_ERR_OK){
        printf_DMA(PRINT_DEBUG"Card type: 0x%x 0x%x\n", cardTypes[0], cardTypes[1]);
        printf_DMA(PRINT_DEBUG"Card ID: 0x%x 0x%x 0x%x 0x%x\n", cardID[0], cardID[1], cardID[2], cardID[3]);

        addr /= 4;
        errNum = rc522_card_auth_state(rc, authMode, addr*4+3, key, cardID);
        if(errNum == RC522_ERR_OK){
            printf_DMA(PRINT_DEBUG"Check password successed.\n");
        }else {
            printf_DMA(PRINT_WARNNING"Check password Failed!\n");
            return RC522_ERR_PASSWORD;
        }
    }else {
        return errNum;
    }

    comBuf[0] = CARD_READ;
    comBuf[1] = addr*4;
    rc522_card_CRC(rc, comBuf, 2, &comBuf[2]);

    errNum = rc522_card_communication(rc, RC522_CMD_Transceive, comBuf, 4, comBuf, &comLen);
    if((errNum == RC522_ERR_OK) && (comLen == 0x90)){
        for(i = 0; i < 16; i ++){
            *(data + i) = comBuf[i];
            printf_DMA(PRINT_DEBUG"block[%d] = 0x%x\n", i, comBuf[i]);
        }
    }else {
        errNum = RC522_ERR_ERR;
    }

    return errNum;
}

uint8_t rc522_card_write_block(struct rc522Stu *rc, uint8_t authMode, uint8_t addr, uint8_t *key, uint8_t *data, uint8_t *cardID){
    uint8_t errNum, i;
    uint32_t comLen;
    uint8_t comBuf[RC522_REC_MAXLEN];

    errNum = rc522_card_identificate(rc, cardTypes, cardID);
    if(errNum == RC522_ERR_OK){
        printf_DMA(PRINT_DEBUG"Card type: 0x%x 0x%x\n", cardTypes[0], cardTypes[1]);
        printf_DMA(PRINT_DEBUG"Card ID: 0x%x 0x%x 0x%x 0x%x\n", cardID[0], cardID[1], cardID[2], cardID[3]);

        addr /= 4;
        errNum = rc522_card_auth_state(rc, 0x60, addr*4+3, key, cardID);
        if(errNum == RC522_ERR_OK){
            printf_DMA(PRINT_DEBUG"Check password successed.\n");
        }else {
            printf_DMA(PRINT_WARNNING"Check password Failed!\n");
            return RC522_ERR_PASSWORD;
        }
    }else {
        return errNum;
    }

    comBuf[0] = CARD_WRITE;
    comBuf[1] = addr*4;
    rc522_card_CRC(rc, comBuf, 2, &comBuf[2]);

    errNum = rc522_card_communication(rc, RC522_CMD_Transceive, comBuf, 4, comBuf, &comLen);
    if((errNum != RC522_ERR_OK) || (comLen != 4) || ((comBuf[0] & 0x0F) != 0x0A)){
        errNum = RC522_ERR_ERR;
    }
    if(errNum == RC522_ERR_OK){
        for(i = 0; i < 16; i ++){
            comBuf[i] = *(data + i);
        }
        rc522_card_CRC(rc, comBuf, 16, &comBuf[16]);
        errNum = rc522_card_communication(rc, RC522_CMD_Transceive, comBuf, 18, comBuf, &comLen);
        if((errNum != RC522_ERR_OK) || (comLen != 4) || ((comBuf[0] & 0x0F) != 0x0A)){
            errNum = RC522_ERR_ERR;
        }
    }

    return errNum;
}
